package com.car.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import com.alipay.api.internal.util.AlipaySignature;
import com.car.commons.core.model.Result;
import com.car.commons.web.util.RedisKeyUtil;
import com.car.commons.web.util.RedisUtil;
import com.car.commons.web.util.StateUtil;
import com.car.order.annotation.ServeOrderLogAnnotation;
import com.car.order.client.CarAccountClient;
import com.car.order.client.CarServeClient;
import com.car.order.client.model.account.user.UserDto;
import com.car.order.client.model.clerk.ClerkDto;
import com.car.order.client.model.serve.serveInfo.ServeInfoDto;
import com.car.order.client.model.serve.serveProject.ServeProjectDto;
import com.car.order.client.model.stores.StoresDto;
import com.car.order.config.AlipayConfiguration;
import com.car.order.dto.alipay.PagePayParam;
import com.car.order.dto.goodOrderInfo.PayOrderForm;
import com.car.order.dto.serviceOrderInfo.ServeOrderDetailDto;
import com.car.order.dto.serviceOrderInfo.ServiceOrderInfoCreatDto;
import com.car.order.dto.serviceOrderInfo.ServiceOrderInfoDto;
import com.car.order.entity.ServeOrderItem;
import com.car.order.entity.ServeOrderLog;
import com.car.order.entity.ServiceOrderInfo;
import com.car.order.entity.form.serveOrderInfo.*;
import com.car.commons.core.model.WoniuException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.car.order.entity.param.serviceOrderInfo.AddReviewParam;
import com.car.order.entity.param.serviceOrderInfo.ServiceOrderInfoInsertParam;
import com.car.order.exception.serveOrderInfo.ServeOrderInfoException;
import com.car.order.exception.serveOrderInfo.ServeOrderInfoExceptionCode;
import com.car.order.mapper.ServeOrderItemMapper;
import com.car.order.mapper.ServiceOrderInfoMapper;
import com.car.order.service.ServeOrderItemService;
import com.car.order.service.ServeOrderLogService;
import com.car.order.service.ServiceOrderInfoService;
import com.car.order.util.AlipayUtil;
import com.car.order.util.PageDtoUtil;
import com.car.order.util.ServeOrderDescConstants;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * @author 杜岷芫
 * @since 2024-08-29 10:40:34
 */
@Service
@Slf4j
public class ServiceOrderInfoServiceImpl extends ServiceImpl<ServiceOrderInfoMapper, ServiceOrderInfo> implements ServiceOrderInfoService {

    @Resource
    private ServiceOrderInfoMapper serviceOrderInfoMapper;
    @Resource
    private CarAccountClient carAccountClient;
    @Resource
    private CarServeClient carServeClient;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private AlipayUtil alipayUtil;
    @Resource
    private AlipayConfiguration alipayConfiguration;
    @Resource
    private ServeOrderItemService serveOrderItemService;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private ServeOrderLogService serveOrderLogService;

    @Override
    public Page<ServiceOrderInfoDto> findPage(ServiceOrderInfoFindPageForm form) {
        Result<ClerkDto> result = carAccountClient.findClerkById(form.getClerkId());
        if (result.getCode() != 200) {
            throw new WoniuException(result.getCode(), result.getMsg());
        }
        ClerkDto clerkDto = result.getData();
        if (clerkDto == null) {
            throw new WoniuException(500, "门店管理员不存在");
        }
        Page<ServiceOrderInfo> page = new Page<>(form.getPageNum()==null?1:form.getPageNum(),form.getPageSize()==null?6:form.getPageSize());
        QueryWrapper<ServiceOrderInfo> query = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(form.getServeOrderId())) {
            query.like("serve_order_id", form.getServeOrderId());
        }
        if (ObjectUtil.isNotEmpty(form.getOrderState())) {
            query.eq("order_state", form.getOrderState());
        }
        query.eq("stores_id", clerkDto.getStoresId());
        Page<ServiceOrderInfo> serviceOrderInfoPage = serviceOrderInfoMapper.selectPage(page, query);
        Page<ServiceOrderInfoDto> serviceOrderInfoDtoPage = PageDtoUtil.convertPage(serviceOrderInfoPage,ServiceOrderInfoDto.class);
        return serviceOrderInfoDtoPage;
    }

    @Override
    public List<ServiceOrderInfo> findList(ServiceOrderInfoFindListForm form){
        QueryWrapper<ServiceOrderInfo> query = new QueryWrapper<>();
        return serviceOrderInfoMapper.selectList(query);
    }

    @Override
    public ServiceOrderInfo findById(String id) {
        return serviceOrderInfoMapper.selectById(id);
    }

    @Override
    @ServeOrderLogAnnotation(desc = ServeOrderDescConstants.USER_CREATE)
    public ServiceOrderInfoCreatDto insert(ServiceOrderInfoInsertParam form) throws Exception{
        //判断用户
        Result<UserDto> result = carAccountClient.findUserById(form.getUserId());
        if (result.getCode() != 200) {
            throw new WoniuException(result.getCode(), result.getMsg());
        }
        UserDto userDto = result.getData();
        if (ObjectUtil.isEmpty(userDto)) {
            throw new WoniuException(500, "用户不存在");
        }
        if (!userDto.getUserState().equals(StateUtil.USER_STATE_NORMAL)) {
            throw new WoniuException(500, "用户状态异常");
        }
        //判断门店
        Result<StoresDto> storesDtoResult = carAccountClient.findStoresById(form.getStoresId());
        if (storesDtoResult.getCode() != 200) {
            throw new WoniuException(storesDtoResult.getCode(), storesDtoResult.getMsg());
        }
        StoresDto storesDto = storesDtoResult.getData();
        if (ObjectUtil.isEmpty(storesDto)) {
            throw new WoniuException(500, "该门店不存在");
        }
        if (!storesDto.getStoresState().equals(StateUtil.STORES_STATE_TRADE)) {
            throw new WoniuException(500, "门店状态异常");
        }
        //判断服务
        Result<ServeInfoDto> serveResult = carServeClient.findServeInfoListById(form.getServeId());
        if (serveResult.getCode() != 200) {
            throw new WoniuException(serveResult.getCode(), serveResult.getMsg());
        }
        ServeInfoDto serveInfoDto = serveResult.getData();
        if (ObjectUtil.isEmpty(serveInfoDto)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_ORDER_INFO_NOT_EXIST);
        }
        if (serveInfoDto.getServeState().equals(StateUtil.SERVE_STATE_DISABLE)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_INFO_STATE_ERROR);
        }

        //获取服务项目
        Result<List<ServeProjectDto>> result1 = carServeClient.findServeProjectListByServeId(serveInfoDto.getServeId());
        if (result1.getCode() != 200) {
            throw new WoniuException(result1.getCode(), result1.getMsg());
        }

        //生成订单
        ServiceOrderInfo serviceOrderInfo = BeanUtil.toBean(form, ServiceOrderInfo.class);
        //生成订单号
        Snowflake snowflake = new Snowflake(1, 1);
        String idStr = snowflake.nextIdStr();
        serviceOrderInfo.setServeOrderId(idStr);
        //生成订单详情

        serviceOrderInfo.setOrderDetail(BeanUtil.toBean(serveInfoDto, ServeOrderDetailDto.class));
        //订单生成时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        serviceOrderInfo.setOrderCreatTime(LocalDateTime.now().format(formatter));
        //价格
        serviceOrderInfo.setMoney(serveInfoDto.getServePrice());
        boolean save = save(serviceOrderInfo);
        if (!save) {
            throw new WoniuException(500, "新增失败");
        }
        ServiceOrderInfoCreatDto serviceOrderInfoCreatDto = BeanUtil.toBean(serviceOrderInfo, ServiceOrderInfoCreatDto.class);
        //生成服务进度
        ArrayList<ServeOrderItem> serveOrderItems = new ArrayList<>();
        List<ServeProjectDto> data = result1.getData();
        for (ServeProjectDto datum : data) {
            ServeOrderItem serveOrderItem = new ServeOrderItem();
            serveOrderItem.setServeOrderId(idStr);
            serveOrderItem.setServeItemId(datum.getProjectId());
            serveOrderItem.setServeItemName(datum.getProjectName());
            serveOrderItem.setSort(datum.getSortValue());
            serveOrderItems.add(serveOrderItem);
        }
        System.out.println(serveOrderItems);
        boolean b = serveOrderItemService.saveBatch(serveOrderItems);
        if (!b) {
            throw new WoniuException(500, "新增服务进度失败");
        }
        //订单进入延迟队列
        rabbitTemplate.convertAndSend("serve_order_check_delay_queue", idStr);
        //redis中存储最后支付期限
        LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(15);
        //转时间戳
        long time = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        redisUtil.saveObject(RedisKeyUtil.payOrderTime(idStr), time + "", 15 * 60);

        return serviceOrderInfoCreatDto;
    }

    @Override
    public ServiceOrderInfo update(ServiceOrderInfoUpdateForm form) {
        ServiceOrderInfo serviceOrderInfo = BeanUtil.toBean(form, ServiceOrderInfo.class);
        boolean b = updateById(serviceOrderInfo);
        if (!b) {
            throw new WoniuException(500, "修改失败");
        }
        return serviceOrderInfo;
    }

    @Override
    public void delete(Integer id) {
        int i=serviceOrderInfoMapper.deleteById(id);
        if (i == 0) {
            throw new WoniuException(500, "删除失败");
        }
    }

    @Override
    public Page<ServiceOrderInfoDto> findPageByUserId(ServiceOrderInfoFindPageByUserIdForm form) {
        Page<ServiceOrderInfo> page = new Page<>(form.getPageNum()==null?1:form.getPageNum(),form.getPageSize()==null?6:form.getPageSize());
        QueryWrapper<ServiceOrderInfo> query = new QueryWrapper<>();
        query.eq("user_id", form.getUserId());
        if (ObjectUtil.isNotEmpty(form.getServeOrderId())) {
            query.like("serve_order_id", form.getServeOrderId());
        }
        if (ObjectUtil.isNotEmpty(form.getOrderState())) {
            query.eq("order_state", form.getOrderState());
        }
        Page<ServiceOrderInfo> serviceOrderInfoPage = serviceOrderInfoMapper.selectPage(page, query);
        Page<ServiceOrderInfoDto> serviceOrderInfoDtoPage = PageDtoUtil.convertPage(serviceOrderInfoPage,ServiceOrderInfoDto.class);
        return serviceOrderInfoDtoPage;
    }

    @Override
    @ServeOrderLogAnnotation(desc = ServeOrderDescConstants.USER_PAID)
    public String payOrder(PayOrderForm form, Integer userId) throws Exception {
        ServiceOrderInfo serviceOrderInfo = serviceOrderInfoMapper.selectById(form.getOrderId());
        if (ObjectUtil.isEmpty(serviceOrderInfo)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_ORDER_INFO_NOT_EXIST);
        }
        if (!serviceOrderInfo.getOrderState().equals(StateUtil.SERVE_ORDER_STATE_UNPAID)) {
            throw new WoniuException(500, "该订单状态异常");
        }
        if (!redisUtil.hasKey(RedisKeyUtil.payOrderTime(form.getOrderId()))) {
            throw new WoniuException(500, "订单已超时");
        }
        long time = Long.parseLong(redisUtil.getObject(RedisKeyUtil.payOrderTime(form.getOrderId())).toString());
        long now = System.currentTimeMillis();
        if ((time - now) / 1000 < 60) {
            throw new Exception("订单已超时");
        }
        PagePayParam param = new PagePayParam();
        //以下参数根据实际情况设置l
        param.setMoney(serviceOrderInfo.getMoney().doubleValue());
        param.setSubject("订单支付");
        param.setBody("");
        param.setReturnUrl(form.getReturnUrl());
        param.setNotifyUrl("http://iqq6v9.natappfree.cc/serviceOrderInfo/notify");
        param.setPayTimeBorder(15);
        param.setOrderId(form.getOrderId());
        String page = alipayUtil.pagePay(param);
        return page;
    }

    @Override
    public void payNotify(HashMap<String, String> params) throws Exception{
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfiguration.getAlipayPublicKey(), "utf-8", "RSA2");
        if (!signVerified){ throw new WoniuException(500,"支付宝验签不通过");}
        String orderId = params.get("out_trade_no");
        String tradeStatus = params.get("trade_status");
        String payTime = params.get("gmt_payment");
        //更新
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            ServiceOrderInfo serviceOrderInfo = serviceOrderInfoMapper.selectById(orderId);
            //修改订单状态
            if (serviceOrderInfo.getOrderState().equals(StateUtil.SERVE_ORDER_STATE_UNPAID)) {
                serviceOrderInfo.setOrderState(StateUtil.SERVE_ORDER_STATE_NOT_SERVED);
            }
            //支付时间
            LocalDateTime localDateTime = LocalDateTime.parse(payTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            serviceOrderInfo.setOrderPayTime(localDateTime.toString());
            //生成服务核验码
            Snowflake snowflake = new Snowflake(1, 1);
            serviceOrderInfo.setVerificationCode(snowflake.nextIdStr());
            serviceOrderInfoMapper.updateById(serviceOrderInfo);

        }
    }

    @Override
    public ServiceOrderInfoDto changeState(ServeOrderInfoChangeStateForm form) {
        ServiceOrderInfo serviceOrderInfo = serviceOrderInfoMapper.selectById(form.getOrderId());
        if (ObjectUtil.isEmpty(serviceOrderInfo)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_ORDER_INFO_NOT_EXIST);
        }
        ServeOrderLog serveOrderLog = new ServeOrderLog();
        serveOrderLog.setServeOrderId(form.getOrderId());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = LocalDateTime.now().format(formatter);
        serveOrderLog.setLogTime(format);
        //如果要取消订单
        if (form.getState().equals(StateUtil.SERVE_ORDER_STATE_CANCEL)) {
            if (!serviceOrderInfo.getOrderState().equals(StateUtil.SERVE_ORDER_STATE_UNPAID)) {
                throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_INFO_STATE_ERROR);
            }
            serviceOrderInfo.setOrderState(form.getState());
            int i = serviceOrderInfoMapper.updateById(serviceOrderInfo);
            if (i != 1) {
                throw new ServeOrderInfoException(500, "修改商品订单失败");
            }
            serveOrderLog.setLogDesc("用户取消订单");
        }
        //如果使用订单
        if (form.getState().equals(StateUtil.SERVE_ORDER_STATE_NOT_EVALUATE)) {
            if (!serviceOrderInfo.getOrderState().equals(StateUtil.SERVE_ORDER_STATE_NOT_SERVED)) {
                throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_INFO_STATE_ERROR);
            }
            serviceOrderInfo.setOrderState(form.getState());
            int i = serviceOrderInfoMapper.updateById(serviceOrderInfo);
            if (i != 1) {
                throw new ServeOrderInfoException(500, "修改商品订单失败");
            }
            serveOrderLog.setLogDesc("用户使用订单");
        }
        boolean save = serveOrderLogService.save(serveOrderLog);
        if (!save) {
            throw new WoniuException(500, "新增服务订单日志失败");
        }
        return BeanUtil.toBean(serviceOrderInfo, ServiceOrderInfoDto.class);
    }

    @Override
    public ServiceOrderInfoDto verification(String verificationCode) {
        ServiceOrderInfo serviceOrderInfo = serviceOrderInfoMapper.selectOne(new QueryWrapper<ServiceOrderInfo>().eq("verification_code", verificationCode));
        if (ObjectUtil.isEmpty(serviceOrderInfo)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_ORDER_INFO_NOT_EXIST);
        }
        if (!serviceOrderInfo.getOrderState().equals(StateUtil.SERVE_ORDER_STATE_NOT_SERVED)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_INFO_STATE_ERROR);
        }
        serviceOrderInfo.setOrderState(StateUtil.SERVE_ORDER_STATE_NOT_EVALUATE);
        int i = serviceOrderInfoMapper.updateById(serviceOrderInfo);
        if (i == 0) {
            throw new ServeOrderInfoException(500, "更新服务订单状态失败");
        }
        ServiceOrderInfoDto serviceOrderInfoDto = BeanUtil.toBean(serviceOrderInfo, ServiceOrderInfoDto.class);
        return serviceOrderInfoDto;
    }

    @Override
    public void addReview(AddReviewParam param) {
        ServiceOrderInfo serviceOrderInfo = serviceOrderInfoMapper.selectById(param.getOrderId());
        if (ObjectUtil.isEmpty(serviceOrderInfo)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_ORDER_INFO_NOT_EXIST);
        }
        if (!serviceOrderInfo.getOrderState().equals(StateUtil.SERVE_ORDER_STATE_NOT_EVALUATE)) {
            throw new ServeOrderInfoException(ServeOrderInfoExceptionCode.SERVE_INFO_STATE_ERROR);
        }
        QueryWrapper<ServiceOrderInfo> qw = new QueryWrapper<>();
        qw.eq("serve_id", serviceOrderInfo.getServeId());
        qw.eq("order_state", StateUtil.SERVE_ORDER_STATE_COMPLETED);
        List<ServiceOrderInfo> serviceOrderInfos = serviceOrderInfoMapper.selectList(qw);
        Double newScore = 0.0;
        if (serviceOrderInfos != null && serviceOrderInfos.size() != 0) {
            for (ServiceOrderInfo orderInfo : serviceOrderInfos) {
                newScore += orderInfo.getScore();
            }
            newScore = (newScore + param.getRating())/serviceOrderInfos.size();
        }else {
            newScore = newScore+param.getRating();
        }
        //修改服务评分
        ServeInfoDto serveInfoDto = new ServeInfoDto();
        serveInfoDto.setServeId(serviceOrderInfo.getServeId());
        serveInfoDto.setScore(newScore);
        Result result = carServeClient.changeServeScore(serveInfoDto);
        if (result.getCode() != 200) {
            throw new WoniuException(result.getCode(), result.getMsg());
        }
        //修改门店评分
        Result result1= carAccountClient.changeStoresInfoScore(param.getRating(),serviceOrderInfo.getStoresId());
        if (result1.getCode() != 200) {
            throw new WoniuException(result1.getCode(), result1.getMsg());
        }
    }
}